package com.goldsprite.gameframeworks.ecs.entity;

import com.goldsprite.gameframeworks.ecs.ComponentManager;
import com.goldsprite.gameframeworks.ecs.IRunnable;
import com.goldsprite.gameframeworks.ecs.component.IComponent;
import com.goldsprite.gameframeworks.ecs.component.TransformComponent;
import com.goldsprite.gameframeworks.ecs.enums.ManageMode;
import com.goldsprite.gameframeworks.ecs.system.GameSystem;

import java.lang.reflect.Field;
import java.util.*;

import com.goldsprite.gameframeworks.log.Debug;
import com.goldsprite.gameframeworks.ecs.IRunnable.*;
import com.goldsprite.gameframeworks.utils.StringUtils;

public class GObject implements IRunnable {
	private IRunnableFields fields = new IRunnableFields();
	private String tag = "";
	private boolean isDestroyed;
	private boolean isEnabled = true; // 添加启用状态字段
	public TransformComponent transform = null;
	private final transient Field transformField;
	private final Map<String, List<IComponent>> components = new LinkedHashMap<>();
	private GObject parent;
	private final List<GObject> childGObjects = new ArrayList<>();
	public final Map<String, Object> metaDatas = new LinkedHashMap<>();

	@Override
	public IRunnable.IRunnableFields getIRunnableFields() {
		return fields;
	}

	public GObject() {
		initIRunnable();
		try {
			transformField = getClass().getField("transform");
			transformField.setAccessible(true);
			//自动管理
			GameSystem.manageGObject(this, ManageMode.ADD);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public GObject setTransform() {
		addComponent(new TransformComponent());
		return this;
	}

	public <T extends IComponent> T addComponent(Class<T> clazz) {
		try {
			T comp = clazz.getConstructor().newInstance();
			return addComponent(comp);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public <T extends IComponent> T addComponent(T component) {
		Class clazz = component.getClass();
		if (clazz.equals(TransformComponent.class) && components.containsKey(clazz.getName())) {
			throw new RuntimeException("单个GObject只允许一个Transform组件");
		}

		//获取目标组件列表
		List<IComponent> list = components.get(clazz.getName());
		if (list == null) list = new ArrayList<>();

		//验证是否重复添加
		if (!list.contains(component)) {
			//初始化getTransform()字段
			if (clazz.equals(TransformComponent.class)) {
				try {
					transformField.set(this, component);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
			//添加组件
			list.add(component);
			components.put(clazz.getName(), list);
			component.setGObject(this);
		}
		return component;
	}

	/**
	 * 添加组件但不触发初始化（用于反序列化）
	 */
	public <T extends IComponent> T addComponentWithoutInit(T component) {
		Class<?> clazz = component.getClass();
		if (clazz.equals(TransformComponent.class) && components.containsKey(clazz.getName())) {
			throw new RuntimeException("单个GObject只允许一个Transform组件");
		}

		//获取目标组件列表
		List<IComponent> list = components.get(clazz.getName());
		if (list == null) list = new ArrayList<>();

		//验证是否重复添加
		if (!list.contains(component)) {
			//初始化getTransform()字段
			if (clazz.equals(TransformComponent.class)) {
				try {
					transformField.set(this, component);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
			//添加组件但不调用awake
			list.add(component);
			components.put(clazz.getName(), list);
			component.setGObject(this);
		}
		return component;
	}

	public void removeComponent(IComponent component) {
		//从游戏物体自身中移除
		List<IComponent> list = components.get(component.getClass().getName());
		if (list != null) {
			list.remove(component);
		}
		// 从组件管理器移除
		ComponentManager.unregisterComponent(this, component.getClass(), component);
		ComponentManager.updateEntityComponentMask(this);
	}

	public boolean hasComponent(Class<? extends IComponent> type) {
		String k = type.getName();
		return components.containsKey(k);
	}

	public <T extends IComponent> T getComponent(Class<T> type) {
		return getComponent(type, 0);
	}

	public <T extends IComponent> T getComponent(Class<T> type, int index) {
		try {
			String k = type.getName();
			List<IComponent> list = components.get(k);
			//找到同类型直接返回
			if (list != null) return (T) list.get(index);
				//否则查找是否有type的子类
			else {
				for (String name : components.keySet()) {
					try {
						List<IComponent> v = components.get(name);
						Class<?> superK = Class.forName(name);
						//如果目标type是当前k其子类
						if (type.isAssignableFrom(superK)) {
							return (T) v.get(index);
						}
					} catch (ClassNotFoundException e) {
						throw new RuntimeException(e);
					}
				}
			}
		} catch (RuntimeException ignore) {
		}
		//找不到返回空
		return null;
	}
	public TransformComponent getTransform() {
		return transform;
	}

	public void setParent(GObject parent) {
		if(parent != null){
			this.parent = parent;
			parent.addChild(this);
		}else {
			this.parent.removeChild(this);
			this.parent = null;
		}
	}
	public void addChild(GObject child) {
		if(childGObjects.contains(child)) return;

		childGObjects.add(child);
		GameSystem.manageGObject(child, ManageMode.REMOVE);
	}
	public void removeChild(GObject child) {
		if(!childGObjects.contains(child)) return;

		childGObjects.remove(child);
		GameSystem.manageGObject(child, ManageMode.ADD);
	}

	/**
	 * 获取所有组件映射（用于序列化）
	 */
	public Map<String, List<IComponent>> getComponents() {
		return components;
	}

	public void awake() {
		Debug.logT("GObject", "游戏物体 %s 苏醒", getName());
		for(List<IComponent> compList : components.values())
			for(IComponent comp : compList) {
				comp.awake();
			}
	}

	@Override
	public void fixedUpdate(float fixedDelta){}

	@Override
	public void update(float delta) {
		// 只有当对象启用且未被销毁时才更新组件
		if (isEnabled && !isDestroyed) {
			for (List<IComponent> list : components.values()) {
				for (IComponent component : list) {
					component.update(delta);
				}
			}
			//更新子物体
			for(GObject child : childGObjects) {
				child.update(delta);
			}
		}
	}

	public void drawGizmos() {
		if (!isEnable() || isDestroyed/* || !showGizmos*/) return;

		for (List<IComponent> list : components.values()) {
			for (IComponent component : list) {
				if(component.isEnable()) component.drawGizmos();
			}
		}
	}

	public void destroy() {
		if (isDestroyed) return;

		isDestroyed = true;
		GameSystem.getInstance().addDestroyGObject(this);
	}

	public void destroyImmediate() {
		for (List<IComponent> list : components.values()) {
			for (int i = list.size() - 1; i >= 0; i--) {
				IComponent component = list.get(i);
				component.destroyImmediate();
			}
		}
		components.clear();

		// 从组件管理器完全移除
		ComponentManager.removeEntity(this);

		GameSystem.manageGObject(this, ManageMode.REMOVE);
	}

	public boolean isDestroyed() {
		return isDestroyed;
	}

	public boolean isEnable() {
		return isEnabled;
	}

	public void setEnable(boolean isEnable) {
		this.isEnabled = isEnable;
	}

	@Override
	public String toString() {
		String str = StringUtils.formatString("%s-%s-%s", getClass().getSimpleName(), getName(), getRunnableGid());
		return str;
	}

	public String getTag() {
		return tag;
	}
	public void setTag(String tag) {
		this.tag = tag;
	}
}
